/*
 * @Author: 姜斌
 * @Date: 2024-05-05 15:41:10
 * @LastEditTime: 2024-05-07 09:13:00
 * @LastEditors: 姜斌
 * @Description: 配置文件
 * @FilePath: \be_quna\config\index.js
 */
const pino = require("pino");
const package = require("../package.json");
const dayjs = require("dayjs");
const os = require("node:os");
const mysql = require("mysql2");
// const mysql = require("mysql2/promise");
const Redis = require("ioredis");
const pinoHttp = require("pino-http");
const mode = process.env.MODE;
module.exports = {
  setLogger: () => {
    const hooks = {
      logMethod(inputArgs, method, level) {
        if (inputArgs.length >= 2) {
          const arg1 = inputArgs.shift();
          const arg2 = inputArgs.shift();
          return method.apply(this, [arg2, arg1, inputArgs.join(" ")]);
        }
        return method.apply(this, inputArgs);
      },
    };
    const logger = pino({
      hooks,
      messageKey: "payload",
      nestedKey: "payload",
      mixin(_context, level) {
        return { level_label: logger.levels.labels[level] };
      },
      base: {
        pid: process.pid,
        hostname: os.hostname(),
        mode,
        time_transform: dayjs().format("YYYY-MM-DD HH:mm:ss"),
        logger_version: pino.version,
      },
      transport: {
        targets: [
          {
            target: "pino-pretty",
            options: {
              destination: process.stdout.fd,
              colorize: mode !== "production",
            },
          },
          {
            target: "pino/file",
            options: {
              destination: `${process.cwd()}/log_box/project-logs/${mode}/${dayjs().format(
                "YYYY-MM-DD"
              )}.log`,
              mkdir: true,
              sync: false,
            },
          },
        ],
      },
    });
    // MySQL基础配置
    const pool = mysql.createPool({
      host: "47.94.17.177",
      user: "root",
      port: "3306",
      password: "Root@1234",
      database: "fintopia_activity_db",
      connectionLimit: 10000,
      connectTimeout: 60000,

      // host: "127.0.0.1",
      // user: "root",
      // port: "3306",
      // password: "root",
      // database: "fintopia_activity_db",
      // connectionLimit: 10000,
    });
    // MySQL查询
    const query = (sql, sqlParams) => {
      return new Promise((resolve, reject) => {
        pool.getConnection((err, connection) => {
          if (!err) {
            connection.query(sql, sqlParams, function (err, results, fields) {
              if (err) {
                // sql错误日志
                global.logger.error({
                  code: 500,
                  msg: "invalid request: " + err,
                });
                reject(err);
              } else {
                resolve(results);
                connection.destroy();
              }
            });
          } else {
            reject(err);
          }
        });
      });
    };
    // 封装事务处理函数
    const runTransaction = (sqls, params) => {
      return new Promise((resolve, reject) => {
        pool.getConnection(function (err, connection) {
          // 连接失败 promise直接返回失败
          if (err) {
            return reject(err);
          }
          // 如果 语句和参数数量不匹配 promise直接返回失败
          if (sqls.length !== params.length) {
            connection.release(); // 释放掉
            return reject(new Error("语句与传值不匹配"));
          }
          // 开始执行事务
          connection.beginTransaction((beginErr) => {
            // 创建事务失败
            if (beginErr) {
              connection.release();
              return reject(beginErr);
            }
            // 返回一个promise 数组
            let funcAry = sqls.map((sql, index) => {
              return new Promise((sqlResolve, sqlReject) => {
                const data = params[index];
                connection.query(sql, data, (sqlErr, result) => {
                  if (sqlErr) {
                    return sqlReject(sqlErr);
                  }
                  sqlResolve(result);
                });
              });
            });
            // 使用all 方法 对里面的每个promise执行的状态 检查
            Promise.all(funcAry)
              .then((arrResult) => {
                // 若每个sql语句都执行成功了 才会走到这里 在这里需要提交事务，前面的sql执行才会生效
                // 提交事务
                connection.commit(function (commitErr, info) {
                  if (commitErr) {
                    // 事务回滚，之前运行的sql语句不生效
                    connection.rollback(function (err) {
                      if (err) ;
                      connection.release();
                    });
                    // 返回promise失败状态
                    return reject(commitErr);
                  }

                  connection.release();
                  // 事务成功 返回 每个sql运行的结果 是个数组结构
                  resolve(arrResult);
                });
              })
              .catch((error) => {
                // 多条sql语句执行中 其中有一条报错 直接回滚
                connection.rollback(function () {
                  connection.release();
                  reject(error);
                });
              });
          });
        });
      });
    };

    // 回滚事务
    const rollback = async () => {
      const conn = pool.getConnection();
      conn.rollback();
      console.log("mysql事务发生回滚......rollback");
    };
    // Redis配置
    const connectRedis = () => {
      const client = new Redis({
        host: "47.94.17.177", // redis地址
        port: 6379, //端口
        password: "Root@1234", //密码
        db: 1,
      });

      return new Promise((resolve, reject) => {
        client.on("connect", () => {
          console.log("Redis连接成功111");
          global.connectRedis = client;
          resolve(client);
        });

        client.on("error", (err) => {
          console.error("Redis连接失败:", err);
          reject(err);
        });
      });
    };
    connectRedis();
    global.pool = pool;
    global.query = query;
    global.rollback = rollback;
    global.runTransaction = runTransaction;
    global.logger = logger;
  },
  setHttpLogger: () => {
    return pinoHttp({
      quietReqLogger: true,
      transport: {
        target: "pino-http-print",
        options: {
          destination: process.stdout.fd,
          relativeUrl: true,
          colorize: mode === "development",
          all: true,
          translateTime: true,
          showTime: mode === "development",
        },
      },
    });
  },
};
